#include "types.hpp"
#include "utils.hpp"

#include <boost/algorithm/string.hpp>
#include <ipmid/api.hpp>

#include <regex>
#include "fault_predict_algo.hpp"

namespace ipmi
{
namespace otrd
{
// 创建CE计数器对象  
CECounter counter;
namespace fault_pre
{

enum FaultPreParamType{
    PARAM_ENABLE,
    PARAM_CPU_FUNNEL,
    PARAM_CPU_THRESHOLD,
    PARAM_MEM_FUNNEL,
    PARAM_MEM_THRESHOLD,
};

void registerOtrdFaultPreFunctions() __attribute__((constructor));

static constexpr auto eepromCPUFaultPrePath ="/com/otrd/eeprom/cpuFaultPredict";
static constexpr auto eepromMemPcieFaultPrePath ="/com/otrd/eeprom/memPcieFaultPredict";
static constexpr auto funnelProp = "faultPreFunnel";
// using fault_pre;
static constexpr auto eepromFaultProCtlSwitchPath =
    "/com/otrd/eeprom/faultpre_ctrl";
enum FaultProLevel : uint8_t
{
    FAULT_PRO_DISABLE,
    FAULT_PRO_ENABLE,
};

ipmi::RspType<> setFaultProCtrl(ipmi::Context::ptr ctx, uint8_t state)
{
    if ((state != FAULT_PRO_DISABLE) && (state != FAULT_PRO_ENABLE))
    {
        return ipmi::responseParmOutOfRange();
    }
    CECounter::setEnableStatus((bool)state);
    return ipmi::response(
        otrd::eeprom::setRawData(ctx, eepromFaultProCtlSwitchPath, state));
}



ipmi::RspType<uint8_t> getFaultProCtrl(ipmi::Context::ptr ctx)
{
    uint8_t faultProCtrlMode = 1;
    auto cc = otrd::eeprom::getRawData(ctx, eepromFaultProCtlSwitchPath,
                                         faultProCtrlMode);
    if (cc)
    {
        return ipmi::response(cc);
    }
    CECounter::setEnableStatus((bool)faultProCtrlMode);
    return ipmi::responseSuccess(faultProCtrlMode);
}

RspType<uint8_t> ipmiOtrdGetFaultPreFunnel(ipmi::Context::ptr ctx, uint8_t Type)
{
    uint32_t faultProFunnel = 30;
    std::string dbusPath;
    switch(Type)
    {
        case CPU:
            dbusPath = eepromCPUFaultPrePath;
        break;
        case MEMORY:
        case PCIE:
            dbusPath = eepromMemPcieFaultPrePath;
        break; 
    }
    auto cc = otrd::eeprom::getData(ctx, dbusPath, funnelProp,faultProFunnel);
    if (cc)
    {
        return ipmi::response(cc);
    }
    CECounter::setFunnelParam((DeviceType)Type, faultProFunnel);
    return ipmi::responseSuccess(faultProFunnel);
}

RspType<> ipmiOtrdSetFaultPreFunnel(ipmi::Context::ptr ctx, uint8_t Type, uint8_t FunnelNum)
{
    std::string dbusPath;
    switch(Type)
    {
        case CPU:
            dbusPath = eepromCPUFaultPrePath;
        break;
        case MEMORY:
        case PCIE:
            dbusPath = eepromMemPcieFaultPrePath;
        break; 
    }
    CECounter::setFunnelParam((DeviceType)Type, FunnelNum);
    return ipmi::response(
        otrd::eeprom::setData(ctx, dbusPath, funnelProp, FunnelNum));
}


static constexpr auto thresholdProp = "faultPreThreshold";

RspType<uint32_t> ipmiOtrdGetFaultPreThreshold(ipmi::Context::ptr ctx, uint8_t Type)
{
    uint32_t faultProThreshold = 30000;
    std::string dbusPath;
    switch(Type)
    {
        case PARAM_ENABLE:
            dbusPath = eepromCPUFaultPrePath;
        break;
        case PARAM_:
        case PCIE:
            dbusPath = eepromMemPcieFaultPrePath;
        break; 
    }
    auto cc = otrd::eeprom::getData(ctx, dbusPath, thresholdProp,faultProThreshold);
    if (cc)
    {
        return ipmi::response(cc);
    }
        
    CECounter::setThresholdParam((DeviceType)Type, faultProThreshold);
    return ipmi::responseSuccess(faultProThreshold);
}

RspType<> ipmiOtrdSetFaultPreThreshold(ipmi::Context::ptr ctx, uint8_t Type, uint32_t Threshold)
{
    std::string dbusPath;
    switch(Type)
    {
        case CPU:
            dbusPath = eepromCPUFaultPrePath;
        break;
        case MEMORY:
        case PCIE:
            dbusPath = eepromMemPcieFaultPrePath;
        break; 
    }
    CECounter::setThresholdParam((DeviceType)Type, Threshold);
    return ipmi::response(
        otrd::eeprom::setData(ctx, dbusPath, thresholdProp, Threshold));
}
 
RspType<> ipmiOtrdSetFaultPredict(ipmi::Context::ptr ctx, uint8_t Type, const std::vector<uint8_t>& data)
{
    switch(Type)
    {
        case PARAM_ENABLE:
            return setFaultProCtrl(ctx,data[0]);
        break;
        case PARAM_CPU_FUNNEL:
            return ipmiOtrdSetFaultPreFunnel(ctx,CPU,data[0]);
        break;
        case PARAM_CPU_THRESHOLD:
            return ipmiOtrdSetFaultPreThreshold(ctx,CPU,*((uint32_t *)data.data()));
        break;
        case PARAM_MEM_FUNNEL:
            return ipmiOtrdSetFaultPreFunnel(ctx,MEMORY,data[0]);
        break;
        case PARAM_MEM_THRESHOLD:
            return ipmiOtrdSetFaultPreThreshold(ctx,MEMORY,*((uint32_t *)data.data()));
        break; 
    }
}

RspType<> ipmiOtrdGetFaultPredict(ipmi::Context::ptr ctx, uint8_t Type)
{
    switch(Type)
    {
        case PARAM_ENABLE:
            return getFaultProCtrl(ctx);
        break;
        case PARAM_CPU_FUNNEL:
            return ipmiOtrdGetFaultPreFunnel(ctx,CPU);
        break;
        case PARAM_CPU_THRESHOLD:
            return ipmiOtrdGetFaultPreThreshold(ctx,CPU);
        break;
        case PARAM_MEM_FUNNEL:
            return ipmiOtrdGetFaultPreFunnel(ctx,MEMORY);
        break;
        case PARAM_MEM_THRESHOLD:
            return ipmiOtrdGetFaultPreThreshold(ctx,MEMORY);
        break; 
    }
}


void registerOtrdFaultPreFunctions()
{
    // get fault prediction
    ipmi::registerHandler(prioOemBase, netFnOtrd, cmdGetFaultPredict,
                          ipmi::Privilege::Admin,
                          ipmiOtrdGetFaultPredict);
    
    // set fault prediction
    ipmi::registerHandler(prioOemBase, netFnOtrd, cmdSetFaultPredict,
                          ipmi::Privilege::Admin,
                          ipmiOtrdSetFaultPredict);
             
}

} // namespace uboot_password
} // namespace Otrd
} // namespace ipmi
